﻿using System;
using System.Text;
using vJine.Core.IO.Json;
using System.Reflection;

namespace vJine.Core.IoC {
    public class Class {

        #region Create

        public static object Create(string type) {
            if (string.IsNullOrEmpty(type)) {
                return null;
            }

            return Class.Create(Reflect.GetType(type));
        }

        public static T Create<T>(params object[] Params) {
            if (Params == null || Params.Length == 0) {
                return (T)Class.Create(typeof(T));
            } else {
                return (T)Class.Create(typeof(T), Params);
            }
        }

        public static object Create(Type tClass) {
            Type t = Nullable.GetUnderlyingType(tClass);
            if (t != null) {
                tClass = t;
            }

            if (tClass.IsArray) {
                Type tElement = tClass.GetElementType();
                int[] Lengths = new int[tClass.GetArrayRank()];
                return Array.CreateInstance(tElement, Lengths);
            } else if (tClass == Reflect.@string) {
                return string.Empty;
            } else if (tClass == Reflect.@decimal) {
                return 0.0M;
            } else if (tClass == Reflect.@DateTime) {
                return DateTime.MinValue;
            } else if (tClass.IsPrimitive) {
                return Activator.CreateInstance(tClass);
            } else if (tClass.GetConstructor(Type.EmptyTypes) != null) {
                return Activator.CreateInstance(tClass, true);
            } else// if (tClass.IsByRef | tClass.IsAbstract | tClass.IsInterface)
            {
                throw new CoreException(string.Format("无法实例化类型[{0}]", tClass.ToString()));
            }
        }

        public static object Create(Type type, object[] Params) {
            return Activator.CreateInstance(type, Params);
        }
        #endregion Create

        #region Init

        public static InitJoint Init(Type tObj, Type[] Tparams, Type[] Tgenerics) {
            return new InitJoint(tObj, Tparams, Tgenerics);
        }

        public static InitJoint Init(Type tObj, params Type[] Tparams) {
            return new InitJoint(tObj, Tparams);
        }

        public static InitJoint Init(string TypeName, params string[] Tparams) {
            return
                Class
                    .Init(Reflect.GetType(TypeName), Reflect.GetTypes(Tparams));
        }

        public static object init(Type Tobj, object[] Params) {
            return
                Class
                    .Init(Tobj, Reflect.GetTypes(Params))
                    .Invoke(Params);
        }

        public static object init(Type Tobj, Type[] Tparams, object[] Params) {
            return Class.Init(Tobj, Tparams).Invoke(null, Params);
        }

        public static object init(string Tobj, string[] Tparams, object[] Params) {
            Type tObj = Reflect.GetType(Tobj);
            if (tObj.IsAbstract) {
                return null;
            }

            return
                init(tObj, Tparams == null || Tparams.Length == 0 ? Type.EmptyTypes : Reflect.GetTypes(Tparams), Params);
        }

        public static object init(string Tobj, string[] Tparams, string[] Tgenerics, object[] Params) {
            return Class.Init(
                Reflect.GetType(Tobj), Reflect.GetTypes(Tparams), Reflect.GetTypes(Tgenerics)
                ).Invoke(null, Params);
        }
        #endregion Init

        #region Set

        public static SetJoint Set(Type tObj, string Name) {
            return new SetJoint(tObj, Name);
        }

        public static SetJoint Set(string TypeName, string Name) {
            return Class.Set(Reflect.GetType(TypeName), Name);
        }

        public static void set(Type tObj, string Name, object value) {
            Class
                .Set(tObj, Name)
                .Invoke(null, value);
        }

        public static void set(string TypeName, string Name, object value) {
            Class
                .Set(TypeName, Name)
                .Invoke(null, value);
        }

        public static void set(Type tObj, string Name, object objContext, object value) {
            Class
                .Set(tObj, Name)
                .Invoke(objContext, value);
        }

        public static void set(string TypeName, string Name, object objContext, object value) {
            Class
                .Set(TypeName, Name)
                .Invoke(objContext, value);
        }

        public static void set(object objContext, string Name, object value) {
            Class
                .Set(objContext.GetType(), Name)
                .Invoke(objContext, value);
        }
        #endregion Set

        #region Get

        public static GetJoint Get(Type tObj, string Name) {
            return new GetJoint(tObj, Name);
        }

        public static GetJoint Get(string TypeName, string Name) {
            return Class.Get(Reflect.GetType(TypeName), Name);
        }

        public static GetJoint Get(object objContext, string Name) {
            return Class.Get(objContext.GetType(), Name);
        }

        public static object get(Type tObj, string Name) {
            return Class.Get(tObj, Name).Invoke(null);
        }

        public static object get(Type tObj, object objContext, string Name) {
            return Class.Get(tObj, Name).Invoke(objContext);
        }

        public static object get(string TypeName, string Name) {
            return Class.Get(Reflect.GetType(TypeName), Name).Invoke(null);
        }

        public static object get(string TypeName, string Name, object objContext) {
            return Class.Get(Reflect.GetType(TypeName), Name).Invoke(objContext);
        }

        public static object get(object objContext, string Name) {
            return Class.Get(objContext, Name).Invoke(objContext);
        }
        #endregion Get

        #region Call
        public static CallSignature<Tobj> Call<Tobj>(string Name, params Type[] Tparams) {
            return Emit.GenCaller<Tobj>(Name, Tparams);
        }

        public static CallSignature<Tobj, TReturn> Call<Tobj, TReturn>(string Name, params Type[] Tparams) {
            return Emit.GenCaller<Tobj, TReturn>(Name, Tparams);
        }

        #region
        public static MethodJoint Call(Type tObj, string Name, params Type[] Tparams) {
            return new MethodJoint(tObj, Name, Tparams);
        }

        public static MethodJoint Call(Type tObj, Type[] Tgenerics, string Name, params Type[] Tparams) {
            return new MethodJoint(tObj, Tgenerics, Name, Tparams);
        }

        public static MethodJoint Call(string TypeName, string Name, params string[] Tparams) {
            return Class.Call(Reflect.GetType(TypeName), Name, Reflect.GetTypes(Tparams));
        }

        public static MethodJoint Call(string TypeName, string[] Tgenerics, string Name, params string[] Tparams) {
            return Class.Call(Reflect.GetType(TypeName), Reflect.GetTypes(Tgenerics), Name, Reflect.GetTypes(Tparams));
        }
        #endregion

        #region
        public static object call(Type tObj, string Name, Type[] Tparams, object[] Params) {
            return Class.Call(tObj, Name, Tparams).Invoke(null, Params);
        }

        public static object call(Type tObj, object objContext, string Name, Type[] Tparams, object[] Params) {
            return Class.Call(tObj, Name, Tparams).Invoke(objContext, Params);
        }

        public static object call(string TypeName, string Name, string[] Tparams, object[] Params) {
            return Class.Call(TypeName, Name, Tparams).Invoke(null, Params);
        }

        public static object call(string TypeName, object objContext, string Name, string[] Tparams, object[] Params) {
            return Class.call(Reflect.GetType(TypeName), objContext, Name, Reflect.GetTypes(Tparams), Params);
        }

        public static object call(object objContext, string Name, Type[] Tparams, object[] Params) {
            return Class.Call(objContext.GetType(), Name, Tparams).Invoke(objContext, Params);
        }

        public static object call(object objContext, string Name, string[] Tparams, object[] Params) {
            return Class.Call(objContext.GetType(), Name, Reflect.GetTypes(Tparams)).Invoke(objContext, Params);
        }

        public static object call(object objContext, string Name, params object[] Params) {
            return Class
                .Call(objContext.GetType(), Name, Reflect.GetTypes(Params))
                .Invoke(objContext, Params);
        }
        #endregion
        #endregion Call

        #region Event
        public static EventStatus On<Tobj>(string Name, object objContext, OnRaise<object> Raise, object State) {
            return On<Tobj, object>(Name, objContext, Raise, State);
        }

        public static EventStatus On<Tobj, Tstate>(string Name, object objContext, OnRaise<Tstate> Raise, Tstate State) {
            return Emit.GenEvent<Tobj, Tstate>(Name, objContext, Raise, State);
        }

        public static EventStatus on(Type tObj, string Name, object objContext, OnRaise<object> Raise, object State) {
            return Emit.GenEvent(tObj, Name, objContext, Raise, State);
        }

        public static EventStatus on(string TypeName, string Name, object objContext, OnRaise<object> Raise, object State) {
            return Emit.GenEvent(Reflect.GetType(TypeName), Name, objContext, Raise, State);
        }
        #endregion Event

        #region Helpers
        public static T Parse<T>(string V) {
            if (V == null) {
                return default(T);
            }

            return (T)Class.Parse(V, typeof(T));
        }

        public static T Parse<T>(object V) {
            if(V == null) {
                return default(T);
            }

            return (T)Class.Parse(V, typeof(T));
        }

        public static T Default<T>() {
            return default(T);
        }
        static MethodInfo _Default = 
            new Call<int>(Default<int>).Method.GetGenericMethodDefinition();
        public static object Default(Type Tobj) {
            return _Default.MakeGenericMethod(Tobj).Invoke(null, null);
        }

        public static object Parse(object V, Type Ttarget) {
            if (V != null && V.GetType() != Reflect.@string) {
                return V;
            }

            return Class.Parse(V as string, Ttarget);
        }

        public static object Parse(string V, Type Ttarget) {
            Type Tbase = Nullable.GetUnderlyingType(Ttarget);
            bool IsNullable = false;
            if (Tbase != null) {
                Ttarget = Tbase;
            }
            if (Tbase != null || Ttarget == Reflect.@string || Ttarget.IsClass ) {
                IsNullable = true;
            }

            if (string.IsNullOrEmpty(V)) {
                if (IsNullable) {
                    if (Ttarget == Reflect.@string) {
                        return V;
                    } else {
                        return null;
                    }
                } else {
                    return Class.Default(Ttarget);
                }
            } else if (Ttarget == Reflect.@string || Ttarget == Reflect.@object) {
                return V;
            } else if (Ttarget == Reflect.@type) {
                return Reflect.GetType(V, false);
            } else if (Ttarget == Reflect.@byteArray) {
                return System.Convert.FromBase64String(V);
            } else if(Reflect.IsArray(Ttarget)) {
                string[] vA = V.Split(',');
                Type teParam = Ttarget.GetElementType();
                if(teParam == Reflect.@string) {
                    return vA;
                } else {
                    Array A = Array.CreateInstance(teParam, vA.Length);
                    for(int i = 0, len = vA.Length; i < len; i++) {
                        A.SetValue(Parse(vA[i], teParam), i);
                    }
                    return A;
                }
            } else if (Ttarget.IsEnum) {
                return Enum.Parse(Ttarget, V);
            } else if (Ttarget == Reflect.@bool) {
                return bool.Parse(V);
            } else if (Ttarget == Reflect.@sbyte) {
                return sbyte.Parse(V);
            } else if (Ttarget == Reflect.@byte) {
                return byte.Parse(V);
            } else if (Ttarget == Reflect.@short) {
                return short.Parse(V);
            } else if (Ttarget == Reflect.@ushort) {
                return ushort.Parse(V);
            } else if (Ttarget == Reflect.@int) {
                return int.Parse(V);
            } else if (Ttarget == Reflect.@uint) {
                return uint.Parse(V);
            } else if (Ttarget == Reflect.@long) {
                return long.Parse(V);
            } else if (Ttarget == Reflect.@ulong) {
                return ulong.Parse(V);
            } else if (Ttarget == Reflect.@float) {
                return float.Parse(V);
            } else if (Ttarget == Reflect.@double) {
                return double.Parse(V);
            } else if (Ttarget == Reflect.@decimal) {
                return decimal.Parse(V);
            } else if (Ttarget == Reflect.@DateTime) {
                return DateTime.Parse(V);
            } else {
                throw new CoreException("类型转换失败【{0}】->【{1}】", V, Ttarget.AssemblyQualifiedName);
            }
        }
        #endregion
    }
}
